package gameEngine.experiments;

import java.util.ArrayList;
import java.util.Random;

import org.apache.log4j.Logger;

import exportSystem.Formater.CSVFormater;
import exportSystem.statistics.ExperimentLog;
import exportSystem.statistics.Statistics;

import gameEngine.agents.AdaptiveAgent;
import gameEngine.agents.Agent;
import gameEngine.agents.observationSystem.Observation;
import gameEngine.agents.teamMateModel.AgentMock;
import gameEngine.environment.Environment;
import gameEngine.game.Game;
import gameEngine.game.TurnBasedScoredGame;

public class ExperimentImpl implements Experiment {

	int numberOfReturns;
	int turns;
	Environment env;
	Observation observation;
	ArrayList<Agent> studies;
	ArrayList<Agent> control;
	ArrayList<AdaptiveAgent> loggingAdaptiveAgents;
	Random generator=new Random();
	ExperimentLog log;
	Logger log4j = Logger.getLogger(ExperimentImpl.class);
	
	public ExperimentImpl(int returns,int turns){
		studies=new ArrayList<Agent>();
		control=new ArrayList<Agent>();
		loggingAdaptiveAgents=new ArrayList<AdaptiveAgent>();
		numberOfReturns=returns;
		this.turns=turns;
		
	}
	
	public void addAdaptiveAgent(Agent agent){
		studies.add(agent);
	}
	
	public void addBasicAgent(Agent agent){
		control.add(agent);
	}
	
	public void setEnvironment(Environment env){
		this.env=env;
	}
	
	public void setObservation(Observation obs){
		this.observation=obs;
	}
	
	public void addGame(Game game) {
		// TODO Auto-generated method stub

	}

	/*
	 * Algorithm:
	 * for each return create a new game from a clone of 1 agent from the study group
	 * and clones of all Agents from the control Group
	 * run the games
	 * @see gameEngine.experiments.Experiment#run()
	 */
	public void run() {
		int counter=0;
		int studyNum=studies.size();
		int controlNum=control.size();
		int stud[]=new int[studyNum];
		for(int i=0;i<studyNum;i++){
			stud[i]=studies.get(i).getID();
		}
		int con[]=new int[controlNum];
		for(int i=0;i<controlNum;i++){
			con[i]=control.get(i).getID();
		}
		log=ExperimentLog.getInstance();
		log.initExperimentLog(turns,numberOfReturns,stud,con);
		
		//for each rerun of the games
		while(counter<numberOfReturns){
			double randomComp[]=new double[controlNum];
			double randomEpsilon[]=new double[controlNum];
			for(int i=0;i<controlNum;i++){
				randomComp[i]=generator.nextDouble();
				randomEpsilon[i]=generator.nextDouble();
			}
			double highScore=0.0;
			int winingGameNum=0;
			//create a game from each study agent
			for(int i=0;i<studyNum;i++){
				ArrayList<Agent> agents=new ArrayList<Agent>();
				//add 1 study
				agents.add(studies.get(i).clone());
				//add all control group
				for(int j=0;j<controlNum;j++){
					Agent copy=control.get(j).clone();
					if(copy.getCompetence()==0)
						copy.setCompetence(randomComp[j]);
					if(copy.getEpsilonGreedy()==0)
						copy.setEpsilonGreedy(randomEpsilon[j]);
					agents.add(copy);
				}
				//set the new team mate model
				for(Agent a:agents){
					a.initClonesModel(agents);
				}
				log4j.info("game: " +(i+1)+ " round: "+counter);
				TurnBasedScoredGame game=new TurnBasedScoredGame(turns, agents, env, observation,i+1);
				double score=game.play();
				//get game with highest score set it as winner of this run 
				if(score>highScore){
					highScore=score;
					winingGameNum=i;
				}
				//update adaptive result to get average 
				if(agents.get(0) instanceof AdaptiveAgent&&((AdaptiveAgent) agents.get(0)).isLogging){
					int id=agents.get(0).getID();
					AdaptiveAgent logAgent=getLoggingAgent(id);
					if(logAgent==null){
						logAgent=((AdaptiveAgent) agents.get(0)).clone();
						logAgent.initClonesModel(agents);
						loggingAdaptiveAgents.add(logAgent);
					}
					logAgent.getResult().sumMatrix(((AdaptiveAgent)agents.get(0)).getResult());
					ArrayList<AgentMock> agentlist=new ArrayList<AgentMock>();
					agentlist.addAll(((AdaptiveAgent) agents.get(0)).getTeamMateModel().getTeamMates());
					logAgent.getResult().addCompAccurecy(Statistics.calculateAqurecy(agentlist, logAgent.getID()));
					logAgent.getResult().addEpsAccuracy(Statistics.calculateEpsilonAqurecy(agentlist, logAgent.getID()));
				}
			}
			//add winner
			log.addWin(winingGameNum);
			counter++;
		}
		log.write();
		CSVFormater formater=new CSVFormater();
		for(Agent a:loggingAdaptiveAgents){
			if(((AdaptiveAgent)a).isLogging){				
				formater.format(((AdaptiveAgent)a).getResult(), a.getID()+"",
						((AdaptiveAgent)a).getResult().getCompAccuracy(),
						((AdaptiveAgent)a).getResult().getEpsAccuracy());
			}	
		}
	}
	
	private AdaptiveAgent getLoggingAgent(int id){
		for(AdaptiveAgent a:loggingAdaptiveAgents){
			if (a.getID()==id)
				return a;
		}
		return null; 
	}

}
